package adke.managers;

import adke.Util;
import adke.listeners.PowerupListener;
import adke.models.powerups.AbilityPowerup;
import adke.models.powerups.Powerup;
import adke.models.powerups.PropertyPowerup;
import adke.models.powerups.ability.*;
import adke.models.powerups.property.*;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;

// manager die bijhoud wat de deviaties mogen zijn voor powerups
// en welke powerups er aangezet zijn voor de game

public class GamePowerupManager
{
    // we gebruiken class files omdat we niet dezelfde klassen moeten gebruiken
    // nav de class filesinstantieren we nieuwe objecten
    
    private static Class[] properties = new Class[]
    {
        LineThicknessPowerup.class, SpeedPowerup.class, TurnPowerup.class,
        HolePowerup.class
    };
    
    private static Class[] abilities = new Class[]
    {
        //InvincibilityPowerup.class
    };
    
    // deviaties
    private static double speedDev, turnDev;
    private static int lineThicknessDev, holeFrequencyDev, holeLengthDev;
    
    private static long invincibilityDuration;
    
    // listeners voor powerup events
    // dit is een comodification-safe vector aangezien wanneer
    // de AnimationManager wordt genotified dat er een powerup gedropt is
    // deze een animatie maakt die de powerup moet gaan laten zien.
    // die animatie luistert wanneer deze powerup wordt opgepakt.
    private static CopyOnWriteArrayList<PowerupListener> listeners;
    
    // TODO: maak instelbaar door gebruiker
    public GamePowerupManager()
    {
        speedDev = 3;
        turnDev = 3;
        lineThicknessDev = 5;
        holeFrequencyDev = 30;
        holeLengthDev = 2;
        invincibilityDuration = 9000;
        
        listeners = new CopyOnWriteArrayList();
    }
    
    // range waarbinnen we random gebruiken
    public static double getSpeedDeviation()
    {
        return speedDev;
    }
    
    public static double getTurnDeviation()
    {
        return turnDev;
    }
    
    public static int getLineThicknessDeviation()
    {
        return lineThicknessDev;
    }
    
    public static int getHoleFrequencyDeviation()
    {
        return holeFrequencyDev;
    }
    
    public static int getHoleLengthDeviation()
    {
        return holeLengthDev;
    }
    
    public static int getGamePowerupCount()
    {
        return properties.length + abilities.length;
    }
    
    public static long getInvincibilityDuration()
    {
        return invincibilityDuration;
    }
    
    // geef alle powerups die gebruikt mogen worden in deze game
    public static Class[] getGamePowerups()
    {
        return null;
    }
    
    public static Powerup getRandomGamePowerup()
    {
        return getRandomGamePowerup(true, true);
    }
    
    public static Powerup getRandomGamePowerup(boolean abilityAllowed, boolean propertyAllowed)
    {
        Powerup[] powerups = new Powerup[2];
        powerups[0] = getRandomAbilityPowerup();
        powerups[1] = getRandomPropertyPowerup();
        
        // als we mogen kiezen uit beide
        if (abilityAllowed && propertyAllowed)
        {
            // zorg ervoor dat we geen null kiezen
            switch (Util.random(2))
            {
                case 0:
                {
                    // als deze null is mogen we doorgaan voor een property
                    if (powerups[0] != null)
                       return powerups[0]; 
                }
                case 1:
                {
                    // als deze null is hebben we mogelijk nog de ability
                    if (powerups[1] != null)
                    {
                        return powerups[1];
                    }
                    else
                    {
                        // doe case0 nog eens
                        if (powerups[0] != null)
                            return powerups[0];
                    }
                }
            }
            
            // break en laat de fout zien
            
        }
        
        // als we een ability willen
        else if (abilityAllowed && powerups[0] != null)
        {
            return powerups[0];
        }
        
        // als we een proprty willen
        else if (powerups[1] != null)
        {
            return powerups[1];
        }
        
        // de gewilde powerup = null
        System.err.println("Requesting powerup while no powerups are defined for this game!");
        return null;
    }
    
    private static Powerup instantiatePowerup(Class power)
    {
        if (power == null) return null;
        try
        {
            return (Powerup) power.newInstance();
        } 
        catch (InstantiationException ex)
        {
            ex.printStackTrace();
        } 
        catch (IllegalAccessException ex)
        {
            ex.printStackTrace();
        }
        return null;
    }
    
    public static AbilityPowerup getRandomAbilityPowerup()
    {
        if (abilities.length == 0) return null;
        Class powerup = abilities[Util.random(abilities.length)];
        return (AbilityPowerup) instantiatePowerup(powerup);
    }
    
    public static PropertyPowerup getRandomPropertyPowerup()
    {
        if (properties.length == 0) return null;
        Class powerup = properties[Util.random(properties.length)];
        return (PropertyPowerup) instantiatePowerup(powerup);
    }
    
    // de poweruplistener heeft van twee kanten informatie nodig.
    // van de dropmanager om te weten wat er gedropt wordt
    // en van de spelers om te weten wat er gepakt wordt
    // deze beide klassen geven door deze abstractielaag aan
    // wat er gebeurt.
    // deze laag notified op zijn beurt de poweruplisteners
    
    public static void addPowerupListener(PowerupListener listener)
    {
        if (!listeners.contains(listener))
            listeners.add(listener);
    }
    
    public static void powerupActivated(AbilityPowerup powerup)
    {
        for (PowerupListener listener : listeners)
            listener.powerupActivated(powerup);
    }
    
    public static void powerupDeactivated(AbilityPowerup powerup)
    {
        for (PowerupListener listener : listeners)
            listener.powerupDeactivated(powerup);
    }
    
    public static void powerupDropped(Powerup powerup)
    {
        for (PowerupListener listener : listeners)
            listener.powerupDropped(powerup);
    }
    
    public static void powerupPickedUp(Powerup powerup)
    {
        for (PowerupListener listener : listeners)
            listener.powerupPickedUp(powerup);
    }
}
